package top.jacktgq.itheima.netty.protocol_design.groupchat.protocol;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import top.jacktgq.itheima.netty.protocol_design.groupchat.message.Message;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

/**
 * @Author CandyWall
 * @Date 2021/3/24--11:14
 * @Description 自定义消息编解码器
 */
@Slf4j
// 不能添加@Sharable注解，原因是父类ByteToMessageCode中做了限制，可能会有多线程共享的问题
// 如果想让自己的编解码器处理类可以支持被多线程共享，需要继承MessageToMessageCodec类
//@ChannelHandler.Sharable
public class MessageCodec extends ByteToMessageCodec<Message> {

    private Message message;

    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        // 1. 魔数：4字节
        out.writeBytes(new byte[]{'8', '8', '4', '8'});
        // 2. 版本号：1字节
        out.writeByte(1);
        // 3. 序列化方式：1字节，0：jdk，1：json，2：protobuf，3：hessian
        out.writeByte(0);
        // 4. 消息类型：1字节
        out.writeByte(msg.getMessageType());
        // 5. 请求序号：4字节
        out.writeInt(msg.getSequenceId());

        // 6. 填充：1字节（无实际意义）
        out.writeByte(0xff);

        // 获取内容的字节数组
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(msg);
        byte[] bytes = baos.toByteArray();
        // 7. 正文长度：4字节
        out.writeInt(bytes.length);
        // 8. 消息内容：bytes.length字节
        out.writeBytes(bytes);
        // 一次消息传输总共字节数
        // 魔数 + 版本号 + 序列化方式 + 消息类型 + 请求序号 + 填充位 + 正文长度 + 消息内容
        // 4    + 1     + 1         + 1        + 4       + 1      + 4       +  bytes.length
        // 共计 16 + bytes.length 字节
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 1. 魔数：4字节
        int magicNum = in.readInt();
        // 2. 版本号：1字节
        byte version = in.readByte();
        // 3. 序列化方式：1字节，0：jdk，1：json，2：protobuf，3：hessian
        byte serializerType = in.readByte();
        // 4. 消息类型：1字节
        byte msg_type = in.readByte();
        // 5. 请求序号：4字节
        int sequenceId = in.readInt();
        // 6. 先读取一个字节的填充位
        in.readByte();
        // 7. 正文长度：4字节
        int msg_length = in.readInt();
        // 8. 消息内容：bytes.length字节
        byte[] bytes = new byte[msg_length];
        in.readBytes(bytes);

        if (serializerType == 0) {
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            Message message = (Message) ois.readObject();
            log.debug("魔数：{}，版本号：{}，序列化方式：{}，消息类型：{}，请求序号：{}，正文长度：{}", magicNum, version, serializerType, msg_type, sequenceId, msg_length, msg_length);
            log.debug("消息内容：{}", message);
            out.add(message);
        }
    }
}
